home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 5 / Apprentice-Release5.iso / Source Code / C / Games / Abalone 1.4.2 / src / Board.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-09-21  |  7.9 KB  |  416 lines  |  [TEXT/MPS ]

  1. #define BOARD_C
  2. #include "Board.h"
  3. #undef BOARD_C
  4.  
  5. #pragma segment More
  6.  
  7. static Board gBoard[kBoardSaved];
  8.  
  9. //    gBoard[0] = current board
  10. //    gBoard[1] = board before last move
  11. //    etc.
  12.  
  13.  
  14.  
  15.  
  16. short
  17. AutoPlay (void)
  18. {
  19.     MoveData    move;
  20.     short        value;
  21.     short        player = gTheGame.CurrentPlayer;
  22.     short        strat = gSet.Strategy[player];
  23.     short        level = gTheGame.CurrentMove > gStrategies[strat].FastOpen
  24.                         ?    gSet.Level[player]
  25.                         :    0;
  26.  
  27.     
  28.     if (gSet.PlayerKind[player] != macPlayer || gInterrupted)
  29.         return empty;
  30.         
  31.     gMoveStartTicks = TickCount();
  32.  
  33.     switch (gStrategies[strat].Type)
  34.     {
  35.         case boardMiniMax:
  36.         
  37.             gCurrentValue = (*(gStrategies[strat].JudgeProc.boardProc)) (& gBoard[0], player);
  38.  
  39.         //    gCurrentValue can be used to measure the progress made.
  40.                 
  41.             value = FindBestBoard    (    & gBoard[0],
  42.                                         gStrategies[strat].JudgeProc.boardProc,
  43.                                         player,
  44.                                         move,
  45.                                         level,
  46.                                         gStrategies[strat].PruneProc,
  47.                                         kMinJudgeVal,
  48.                                         kMaxJudgeVal
  49.                                     );
  50.         break;
  51.  
  52.         case boardMiniMaxNoFliche:
  53.         
  54.             gCurrentValue = (*(gStrategies[strat].JudgeProc.boardProc)) (& gBoard[0], player);
  55.  
  56.         //    gCurrentValue can be used to measure the progress made.
  57.                 
  58.             value = FindGoodBoard    (    & gBoard[0],
  59.                                         gStrategies[strat].JudgeProc.boardProc,
  60.                                         player,
  61.                                         move,
  62.                                         level,
  63.                                         gStrategies[strat].PruneProc,
  64.                                         kMinJudgeVal,
  65.                                         kMaxJudgeVal
  66.                                     );
  67.         break;
  68.  
  69.         case boardMiniMaxGreedy:
  70.         
  71.             gCurrentValue = (*(gStrategies[strat].JudgeProc.boardProc)) (& gBoard[0], player);
  72.  
  73.         //    gCurrentValue can be used to measure the progress made.
  74.                 
  75.             value = FindNiceBoard    (    & gBoard[0],
  76.                                         gStrategies[strat].JudgeProc.boardProc,
  77.                                         player,
  78.                                         move,
  79.                                         level
  80.                                     );
  81.         break;
  82.  
  83.         case moveMiniMax:
  84.         
  85.             value = FindBestMove    (    & gBoard[0],
  86.                                         gStrategies[strat].JudgeProc.moveProc,
  87.                                         player,
  88.                                         move,
  89.                                         level,
  90.                                         kMinJudgeVal,
  91.                                         kMaxJudgeVal
  92.                                     );
  93.         break;
  94.         default:
  95.             Assert (0, UNKNOWN_SEARCH_METHOD);
  96.     }
  97.     
  98.     if (gInterrupted)
  99.         return empty;            //    Ignore the thoughts about the last move.
  100.  
  101.     ProcessMove (move, ! gSet.Balls3D);
  102.  
  103. //    The broadcast is done after the board has been modified:
  104. //    The move is still valid, so we can first send just the move,
  105. //    but if sending the move somehow fails,
  106. //    The whole board is already updated and can be sent 'as is'.
  107.     
  108.     BroadcastMove (move, PriorPlayer (CurrentPlayer()), CheckSum (RecentBoard()));
  109.  
  110.     return EndOfGame();
  111. }
  112.  
  113.  
  114.  
  115. BoardPtr
  116. CurrentBoard (void)
  117. {
  118.     return & gBoard[0];
  119. }
  120.  
  121.  
  122.  
  123. BoardPtr
  124. RecentBoard (void)
  125. {
  126.     return & gBoard[1];
  127. }
  128.  
  129.  
  130.  
  131. Boolean
  132. FieldHasCurrentPlayersBall (Field f)
  133. {
  134.     if (f <= 0 || f > kFields)
  135.         return 0;
  136.         
  137.     return gBoard[0].field[f] == gTheGame.CurrentPlayer;
  138. }
  139.  
  140.  
  141.  
  142. char
  143. FieldOwner (Field f)
  144. {
  145.     return gBoard[0].field[f];
  146. }
  147.  
  148.  
  149.  
  150. void
  151. InitBoard (void)
  152. {
  153.     short b;
  154.     
  155.     for (b = 0; b < kBoardSaved; b++)
  156.         ResetBoard (& gBoard[b]);
  157.     
  158.     SetPort (gAbaloneWindow);
  159.     SetWRefCon (gAbaloneWindow, (long) (& gBoard[0]));
  160.     InvalBoard();
  161. }
  162.  
  163.  
  164.  
  165. static short stackSize = 0;
  166.  
  167.  
  168. short
  169. BoardsOnStack (void)
  170. {
  171.     return stackSize;
  172. }
  173.  
  174.  
  175.  
  176. void
  177. PushBoard (BoardPtr newBoard)
  178. {
  179.     short b;
  180.     
  181.     for (b = kBoardSaved - 1; --b >= 0; )
  182.         CopyBoard (& gBoard[b], & gBoard[b+1]);
  183.     
  184.     CopyBoard (newBoard, & gBoard[0]);
  185.     
  186.     if (stackSize < kBoardSaved) stackSize++;
  187. }
  188.  
  189.  
  190.  
  191. Boolean
  192. PopBoard (void)
  193. {
  194.     short b;
  195.     
  196.     if (stackSize <= 0)
  197.         return 0;
  198.         
  199.     for (b = 0; b < kBoardSaved - 1; b++)
  200.         CopyBoard (& gBoard[b+1], & gBoard[b]);
  201.     
  202.     --stackSize;
  203.     
  204.     return 1;
  205. }
  206.  
  207.  
  208. void
  209. CopyBoard (BoardPtr from, BoardPtr to)
  210. {
  211. #ifdef THINK_C
  212.     asm
  213.     {
  214.         movea.l    from, a0
  215.         movea.l    to, a1
  216.         
  217.         moveq    #20, d0
  218.         
  219.     @1    move.l    (a0)+, (a1)+
  220.         dbra    d0, @1
  221.     }
  222. #elif defined(powerc)
  223.     memcpy (to, from, sizeof (Board));
  224. #else
  225.  
  226. //    I could do this with the better-looking
  227. //    memcpy (to, from, sizeof (Board));
  228. //    the following doesn't look as nice,
  229. //    but you should take a look at the beautiful compiled code it produces...
  230.     
  231.     register long *b1 = (long *) from;
  232.     register long *b2 = (long *) to;
  233.  
  234.     *b2++ = *b1++;
  235.     *b2++ = *b1++;
  236.     *b2++ = *b1++;
  237.     *b2++ = *b1++;
  238.     *b2++ = *b1++;
  239.     *b2++ = *b1++;
  240.     *b2++ = *b1++;
  241.     *b2++ = *b1++;
  242.     *b2++ = *b1++;
  243.     *b2++ = *b1++;
  244.     *b2++ = *b1++;
  245.     *b2++ = *b1++;
  246.     *b2++ = *b1++;
  247.     *b2++ = *b1++;
  248.     *b2++ = *b1++;
  249.     *b2++ = *b1++;
  250.     *b2++ = *b1++;
  251.     *b2++ = *b1++;
  252.     *b2++ = *b1++;
  253.     *b2++ = *b1++;
  254.     *b2++ = *b1++;
  255. #endif
  256. }
  257.  
  258.  
  259.  
  260. Boolean
  261. EqualBoards (BoardPtr b1, BoardPtr b2)
  262. {
  263.     return memcmp (& b1->field[1], & b2->field[1], kFields) == 0;
  264. }
  265.  
  266.  
  267.  
  268. short
  269. EndOfGame (void)
  270. {
  271.     short p;
  272.     
  273.     for (p = 1; p <= gTheGame.Players; p++)
  274.         if (gBoard[0].loot[p-1][0] >= 6)
  275.             return p;
  276.             
  277.     return 0;
  278. }
  279.  
  280.  
  281. //    The official rules of Abalone don't include a KO rule.
  282. //    For the University of Waterloo contest, it has been added to Abalone to avoid
  283. //    an excessive number of games ending in a draw by endless repetition.
  284. //    The KO rule sais, no board may ever repeat.
  285. //    This means, at least theoretically, that in the search for the best board,
  286. //    EVERY possible board should be compared against every board that has ever been.
  287. //    Without special tricks (using hash functions might be a solution),
  288. //    this would seriously degrade the performance of searching.
  289. //    Therefore, I have chosen to follow the KO rule only partially.
  290. //    To avoid serious performance degradation, ONLY the board resulting from
  291. //    the top-level move under investigation is checked.
  292. //
  293. //    This is not illegal, and not directly to our advantage either:
  294. //    we only assume our opponent is able to make some extra moves it cannot really make,
  295. //    making it ourselves a bit more difficult to predict his replies.
  296. //
  297. //    I DO cheat in a different way, however, since I don't compare the resulting
  298. //    board against ALL gone boards, but only against the last kBoardSaved boards.
  299. //    This should not really be a problem, since the probability of a board repeating
  300. //    after a large number of moves has been made is extremely small,
  301. //    even if the players are computers.
  302.  
  303. Boolean
  304. MoveIsKO (MovePtr move, short level, short player)
  305. {
  306.     Board    testBoard;
  307.     
  308.     if (player != gTheGame.CurrentPlayer)
  309.         
  310.     //    of course, The Enemy can also be in a KO postition, but we're not going into that now.
  311.     //    This test has just been added to allow us to play by the rules, nothing more.
  312.         
  313.         return false;
  314.         
  315.     if (level != gSet.Level[player])
  316.         
  317.     //    Since we're only testing the legality,
  318.     //    we just have to deal with a move that would be made immediately.
  319.         
  320.         return false;
  321.                 
  322. //    This is a move that needs some further investigation,
  323. //    since it may result in a direct KO position.
  324.     
  325.     CopyBoard (& gBoard[0], & testBoard);
  326.     if (move[1] == 0)
  327.         DoMove (& testBoard, move);
  328.     else
  329.         DoFlicheMove (& testBoard, move);
  330.     
  331.     return BoardIsKO (& testBoard);
  332. }
  333.  
  334.  
  335.  
  336. Boolean
  337. BoardIsKO (BoardPtr testBoard)
  338. {
  339.     short b;
  340.     
  341.     for (b = 1; b < kBoardSaved; b++)
  342.         if (EqualBoards (& gBoard[b], testBoard))
  343.             return true;
  344.  
  345.     return false;
  346. }
  347.  
  348.  
  349.  
  350. Boolean
  351. ProcessMove (MovePtr move, Boolean animate)
  352. {
  353.     BoardPtr    board = (BoardPtr) GetWRefCon (gAbaloneWindow);
  354.     
  355.     if (move[0] == 0 || move[3] == down)
  356.         return false;
  357.         
  358.     if (move[1] == 0 && ! ValidMove (board, move))
  359.         return false;
  360.         
  361.     if (move[1] != 0 && ! ValidFlicheMove (board, move))
  362.         return false;
  363.  
  364.     ShowNotation (move, board);
  365.     PushBoard (board);
  366.     
  367.     *((long *) & gLastMove) = *((long *) move);
  368.     
  369.     if (move[1] == 0)    //    straight move
  370.     {
  371.         ShowMove (move, animate);
  372.             
  373.         if  (gSet.SoundOn)
  374.             SndPlayMove (board, move, move[3]);
  375.         
  376.         if (DoMove (board, move) == ball_down)
  377.         {
  378.             if (gSet.SoundOn)
  379.                 SndPlayBallDown();
  380.             
  381.             InvalItems (gAbaloneWindow);
  382.         }
  383.     }
  384.     else                //    fliche move
  385.     {
  386.         ShowFlicheMove (move, animate);
  387.         
  388.         if  (gSet.SoundOn)
  389.             SndPlayFlicheMove (board, move, move[3]);
  390.         
  391.         DoFlicheMove (board, move);
  392.     }
  393.  
  394.     gTheGame.CurrentPlayer = NextPlayer (gTheGame.CurrentPlayer);
  395.     gTheGame.CurrentMove++;
  396.     gFileSaved = false;
  397.     UpdateBoard (gAbaloneWindow);
  398.     
  399.     return true;
  400. }
  401.  
  402.  
  403.  
  404. unsigned long
  405. CheckSum (BoardPtr board)
  406. {
  407.     unsigned long    sum = 0L;
  408.     unsigned char    *fp = (unsigned char *) board;
  409.     short i;
  410.     
  411.     for (i = 0; i < 32; i++, fp += 2)
  412.         if (*fp) sum += (1L << i);
  413.         
  414.     return sum;
  415. }
  416.